package com.daffodil.storage.service.impl;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import javax.servlet.http.HttpServletResponse;

import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.ContentDisposition;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;

import com.daffodil.storage.client.FastdfsStorageClient;
import com.daffodil.storage.exception.BaseException;
import com.daffodil.storage.model.Page;
import com.daffodil.storage.model.StorageResult;
import com.daffodil.storage.properties.FastdfsProperties;
import com.daffodil.storage.properties.StorageProperties;
import com.daffodil.storage.service.AStorageService;
import com.github.tobato.fastdfs.domain.fdfs.MetaData;
import com.github.tobato.fastdfs.domain.fdfs.StorePath;
import com.github.tobato.fastdfs.domain.proto.storage.DownloadCallback;

import cn.hutool.core.io.file.FileNameUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * FastdFS分布式存储
 * @author yweijian
 * @date 2023年10月31日
 * @version 1.0
 * @description
 */
@Slf4j
@Service
@Configuration
@ConditionalOnProperty(name = StorageProperties.NAME, havingValue = StorageProperties.FASTDFS)
public class StorageFastdfsServiceImpl extends AStorageService {

    @Autowired
    private StorageProperties storageProperties;

    @Autowired
    private FastdfsStorageClient storageClient;

    @Override
    public List<StorageResult> list(String folder, String name, Page page) {
        return Collections.emptyList();
    }

    @Override
    protected StorageResult upolad(StorageResult result, InputStream inputStream) {
        log.debug("FastdFS对象存储 > 上传对象 > fileName={}", result.getOrigin());

        FastdfsProperties properties = storageProperties.getFastdfs();
        Map<String, String> metadata = result.getMetadata();
        Set<MetaData> metaDatas = new HashSet<MetaData>();
        if(ObjectUtil.isNotEmpty(metadata)) {
            for(Entry<String, String> entry : metadata.entrySet()) {
                metaDatas.add(new MetaData(entry.getKey(), entry.getValue()));
            }
        }
        StorePath storePath = storageClient.uploadFile(properties.getGroupName(), inputStream, result.getSize(), result.getSuffix(), metaDatas);
        if(ObjectUtil.isNotNull(storePath)) {
            String key = storePath.getPath();
            result.setGroup(storePath.getGroup());
            result.setName(FileNameUtil.getName(key));
            result.setPrefix(FileNameUtil.getPrefix(key));
            result.setKey(key);
            result.setUrl(properties.getDomain() + StrUtil.SLASH + key);
            log.debug("FastdFS对象存储 > 上传对象 > path={}", storePath.getPath());
        }

        log.debug("FastdFS对象存储 > 上传对象 > result={}", result.toString());
        return result;
    }

    @Override
    public void download(String key, HttpServletResponse response) {
        FastdfsProperties properties = storageProperties.getFastdfs();
        String fileName = FileNameUtil.getName(key);
        if(ObjectUtil.isEmpty(fileName)) {
            return;
        }

        response.setCharacterEncoding(StandardCharsets.UTF_8.name());
        response.setContentType(MediaType.MULTIPART_FORM_DATA_VALUE);
        response.setHeader(HttpHeaders.CONTENT_DISPOSITION, ContentDisposition.attachment().filename(fileName, StandardCharsets.UTF_8).build().toString());
        try {
            InputStream inputStream = storageClient.downloadFile(properties.getGroupName(), key, new DownloadCallback<InputStream>() {
                @Override
                public InputStream recv(InputStream inputStream) throws IOException {
                    return inputStream;
                }
            });
            IOUtils.copy(inputStream, response.getOutputStream());
        } catch (IOException e) {
            log.error(e.getMessage(), e);
            throw new BaseException(e.getMessage());
        }
    }

    @Override
    public void remove(String key) {
        FastdfsProperties properties = storageProperties.getFastdfs();
        storageClient.deleteFile(properties.getGroupName(), key);
    }

}
